#include <animation/AnimationTrack.h>
#include <animation/Animation.h>

namespace ne
{
    const uint16_t AnimationTrack::MAX_ANIMATION_TRACK_HANDLE = 0xFFFF;

    AnimationTrack::AnimationTrack(Animation *parent, const uint16_t handle)
        : mHandle(handle),
          mpParentAnimation(parent),
          mNeedSort(false)
    {
    }

    uint16_t AnimationTrack::getHandle() const
    {
        return mHandle;
    }

    KeyFrame* AnimationTrack::createKeyFrame(const real time)
    {
        KeyFrame *newKeyFrame = _createKeyFrameImpl(time);
        mKeyFrames.push_back(newKeyFrame);
        _needSort();
        _keyFrameDataChanged();
        return newKeyFrame;
    }

    bool AnimationTrack::destroyKeyFrame(const size_t index)
    {
        if (index < mKeyFrames.size())
        {
            KeyFrameVectorIterator it = mKeyFrames.begin();
            it += index;
            delete *it;
            mKeyFrames.erase(it);
            _keyFrameDataChanged();
            return true;
        }
        return false;
    }

    void AnimationTrack::destroyAllKeyFrames()
    {
        for (KeyFrameVectorIterator it=mKeyFrames.begin(); it!=mKeyFrames.end(); ++it)
        {
            delete *it;
        }
        mKeyFrames.clear();
        mNeedSort = false;
        _keyFrameDataChanged();
    }

    size_t AnimationTrack::getKeyFramesCount() const
    {
        return mKeyFrames.size();
    }

    KeyFrame* AnimationTrack::getKeyFrame(const size_t index) const
    {
        _sort();
        if (index < mKeyFrames.size())
        {
            return mKeyFrames[index];
        }
        return 0;
    }

    const KeyFrameVector& AnimationTrack::getKeyFrameVector() const
    {
        return mKeyFrames;
    }

    void AnimationTrack::_keyFrameDataChanged() const
    {
    }

    AnimationTrack::~AnimationTrack()
    {
        destroyAllKeyFrames();
    }

    void AnimationTrack::_needSort() const
    {
        mNeedSort = true;
    }

    void AnimationTrack::_sort() const
    {
        if (mNeedSort)
        {
            std::sort(mKeyFrames.begin(), mKeyFrames.end(), KeyFrameLess);
            mNeedSort = false;
        }
    }

    void AnimationTrack::_binarySearchKeyFramesAtTime(size_t begin, size_t end, const real time, KeyFrame **beginKeyFrame, KeyFrame **endKeyFrame) const
    {
        while (begin <= end && end < mKeyFrames.size())
        {
            size_t mid = (begin + end) >> 1;
            real keyTime = mKeyFrames[mid]->getTime();
            if (keyTime == time)
            {
                *beginKeyFrame = mKeyFrames[mid];
                *endKeyFrame = 0;
                return;
            }

            if (begin == end)
            {
                if (keyTime < time)
                {
                    *beginKeyFrame = mKeyFrames[mid];
                    if (mid + 1 >= mKeyFrames.size())
                    {
                        *endKeyFrame = 0;
                    }
                    else
                    {
                        *endKeyFrame = mKeyFrames[mid + 1];
                    }
                }
                else if (keyTime > time)
                {
                    *endKeyFrame = mKeyFrames[mid];
                    if (mid <= 0)
                    {
                        *beginKeyFrame = 0;
                    }
                    else
                    {
                        *beginKeyFrame = mKeyFrames[mid - 1];
                    }
                }
                return;
            }

            if (keyTime < time)
            {
                begin = mid + 1;
            }
            else if (keyTime > time)
            {
                end = mid;
            }
        }

        if (begin > end || end >= mKeyFrames.size())
        {
            *beginKeyFrame = 0;
            *endKeyFrame = 0;
            return;
        }
    }

    bool AnimationTrack::KeyFrameLess(const KeyFrame *keyA, const KeyFrame *keyB)
    {
        if (keyA && keyB)
        {
            return keyA->getTime() < keyB->getTime();
        }
        if (keyB)
        {
            return false;
        }
        return true;
    }
}
